package main

import (
	"fmt"
	"time"
)

func main() {
	//test2()
	test()
}

var buildeCount int = 0

func test3() {
	fmt.Println("程序开始")
	exetChan := make(chan bool, 1)
	//exetChan <- false
	go func() {
		time.Sleep(time.Second * 30)
		exetChan <- true
	}()
	// if <-exetChan { ... }：这部分代码会阻塞，直到exetChan通道接收到一个值。
	if <-exetChan {
		fmt.Println("程序结束")
	}
	fmt.Println("end")
}

func test2() {
	fmt.Println("程序开始")
	storageChan := make(chan Product, 100)
	shopChan := make(chan Product, 100)
	exitChan := make(chan bool, 1)

	go Producer(storageChan, 30)
	go Producer(storageChan, 3)
	/*
		for i := 0; i < 10; i++ {
			go Producer(storageChan, 3)
		}	*/
	go Logistics(storageChan, shopChan)
	go Consumer(shopChan, 30, exitChan)
	// <-exitChan 这一步为什么会阻塞等待协程完成呢？
	if <-exitChan {
		fmt.Println("程序结束")
	}
	fmt.Println("buildeCount", buildeCount)
}

func test() {
	fmt.Println("程序开始")
	storageChan := make(chan Product, 10)
	shopChan := make(chan Product, 10)
	exitChan := make(chan bool, 1)

	go Producer(storageChan, 10)
	go Logistics(storageChan, shopChan)
	go Consumer(shopChan, 10, exitChan)
	if <-exitChan {
		fmt.Println("程序结束")
	}
}

type Product struct {
	Name string
}

// 生成者
func Producer(storageChan chan<- Product, count int) {
	fmt.Println("生产者开始生产-------------------------", count)
	for {
		producer := Product{Name: "product" + fmt.Sprint(count)}
		buildeCount++
		storageChan <- producer
		fmt.Println("---------------------- ", &count)
		fmt.Println("生产者 - ", producer.Name)
		count--
		time.Sleep(1000 * time.Millisecond)
		if count < 0 {
			return
		}
	}
}

// 运输
func Logistics(storageChan <-chan Product, shopChan chan<- Product) {
	for {
		product := <-storageChan
		time.Sleep(100 * time.Millisecond)
		fmt.Println("运输了 - ", product.Name)
		shopChan <- product
	}
}

// 消费者
func Consumer(shopChan <-chan Product, count int, exitChan chan bool) {
	for {
		product := <-shopChan
		fmt.Println("消费 --", product.Name)
		count--
		if count < 1 {
			exitChan <- true
			return
		}
	}
}
